package view.GUI.otherView;

import org.controlsfx.dialog.Dialogs;
import org.controlsfx.validation.ValidationSupport;

import model.Configuration;
import model.handler.databaseHandling.DatabaseHandler;
import view.GUI.mainView.MainView;
import view.Validator.NameValidator;
import view.Validator.DoubleNumberRangeValidator;
import view.Validator.IntegerNumberRangeValidator;
import view.Validator.MyValidationSupport;
import view.Validator.PasswordValidator;
import controller.Controller;
import enums.GUIText;
import enums.Message;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.Separator;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;

/**
 * Provides the Login-View.
 * <p>
 * If the administrator wants to log in it is not necessary to enter the number
 * of coins and the actual cash. The textfields are validated by
 * <code>NumberValidation</code>, <code>NickValidation</code> and
 * <code>PasswordValidation</code>. Forwards the login-attempt to the
 * <code>Controller</code> using the MVC-Pattern.
 * 
 * @version %I%, %G%
 * @see NumberValidation
 * @see NickValidation
 * @see PasswordValidation
 * @see Controller
 */
public final class Login extends Application {

	/**
	 * Layout-Manager using a GridPane
	 */
	private GridPane			grid;
	// Textfields for input
	private TextField			txtNickname;
	private TextField			txtPassword;
	private TextField			txtCoins;
	private TextField			txtCash;
	private Label				lblPassword;
	// Normal labels that name the textfield
	private Label				lblNick;
	private Label				lblCoins;
	private Label				lblCash;
	private ValidationSupport	valSup;
	private Button				btnLogin;
	private Scene				scene;
	private Stage				primaryStage;
	
	private Label lblTopic;
	private Separator sepTop;
	private Separator sepBottom;
	
	private int rowCounter;
	
	/**
	 * Reference to the controller
	 */
	private Controller			controller;

	/**
	 * Only constructor.
	 */
	public Login() {

		rowCounter = 1;
		valSup = MyValidationSupport.createDefaultValidationSupport();
		createWidgets();
		setLayout();
		addWidgets();
		setupValidation();
		setupInteraction();
		this.controller = Controller.getInstance();
		controller.setLogin(this);
		// Initializing the database
		DatabaseHandler.initialize();
	}

	/**
	 * Displays a popup for user information with a specified message.
	 * 
	 * @param status
	 * @param msg
	 *            Message to be displayed in the Popup
	 */
	public void loginFailed(Message msg) {

		Dialogs.create().message(msg.toString()).owner(primaryStage).showError();
	}

	/**
	 * Closes the login window and starts the main GUI because the login attempt
	 * was successful.
	 */
	public void loginSuccess(boolean isAdmin) {

		new MainView(isAdmin);
		
		primaryStage.close();
	}

	// HELPER METHODS BELOW
	/**
	 * Forwards a login attempt to the model where the final validity check of
	 * the login attempt is performed.
	 * <p>
	 * Displays popups for user information if the login failed.
	 */
	private void tryLogin() {

		try {
			controller.tryLogin(txtNickname.getText().trim(), txtPassword.getText().trim(), txtCash.getText().trim(), txtCoins.getText().trim());
		} catch (NumberFormatException nfEx) {
			Dialogs.create().message(Message.UNGUELTIGESFORMAT.toString()).owner(primaryStage).showError();
		} catch (IllegalArgumentException ex) {
			Dialogs.create().message(ex.getMessage().toString()).owner(primaryStage).showError();
		}
	}

	/**
	 * This helper-method sets the layout for the whole view.
	 */
	private void setLayout() {

		btnLogin.setDisable(true);
		btnLogin.setPrefSize(100, 25);
		
		txtNickname.setPrefSize(200, 25);
		lblNick.setPrefSize(175, 25);
		
		lblPassword.setPrefSize(175, 25);
		txtPassword.setPrefSize(200, 25);
		
		lblCash.setPrefSize(175, 25);
		txtCash.setPrefSize(200, 25);
		
		lblCoins.setPrefSize(175, 25);
		txtCoins.setPrefSize(200, 25);
		
		sepBottom.setMaxWidth(500);
		sepTop.setMaxWidth(500);
		
		GridPane.setColumnSpan(sepBottom, 3);
		GridPane.setColumnSpan(sepTop, 3);
		
		lblTopic.setId("topic");
	}

	/**
	 * This helper-method adds all Eventhandler provided and needed by this
	 * view.
	 */
	private void setupInteraction() {

		txtCoins.setOnKeyReleased(new EventHandler<KeyEvent>() {

			@Override
			public void handle(KeyEvent e) {
				if (e.getCode() == KeyCode.ENTER && !MyValidationSupport.isNodeToDisable(valSup)) {
					tryLogin();
				}
				btnLogin.setDisable(MyValidationSupport.isNodeToDisable(valSup));
			}
		});
		txtCash.setOnKeyReleased(new EventHandler<KeyEvent>() {

			@Override
			public void handle(KeyEvent e) {
				if (e.getCode() == KeyCode.ENTER && !MyValidationSupport.isNodeToDisable(valSup)) {
					tryLogin();
				}
				btnLogin.setDisable(MyValidationSupport.isNodeToDisable(valSup));
			}
		});
		txtNickname.setOnKeyReleased(new EventHandler<KeyEvent>() {

			@Override
			public void handle(KeyEvent e) {
				if (e.getCode() == KeyCode.ENTER && !MyValidationSupport.isNodeToDisable(valSup)) {
					tryLogin();
				}
				btnLogin.setDisable(MyValidationSupport.isNodeToDisable(valSup));
			}
		});
		txtPassword.setOnKeyReleased(new EventHandler<KeyEvent>() {

			@Override
			public void handle(KeyEvent e) {
				if (e.getCode() == KeyCode.ENTER && !MyValidationSupport.isNodeToDisable(valSup)) {
					tryLogin();
				}
				btnLogin.setDisable(MyValidationSupport.isNodeToDisable(valSup));
			}
		});
		txtCash.setOnKeyReleased(new EventHandler<KeyEvent>() {

			@Override
			public void handle(KeyEvent arg0) {

				btnLogin.setDisable(MyValidationSupport.isNodeToDisable(valSup));
			}
		});
		txtPassword.setOnKeyReleased(new EventHandler<KeyEvent>() {

			@Override
			public void handle(KeyEvent arg0) {

				btnLogin.setDisable(MyValidationSupport.isNodeToDisable(valSup));
			}
		});
		txtNickname.setOnKeyReleased(new EventHandler<KeyEvent>() {

			@Override
			public void handle(KeyEvent arg0) {

				btnLogin.setDisable(MyValidationSupport.isNodeToDisable(valSup));
			}
		});
		// By clicking the Logn-Button a login-attempt is performed.
		btnLogin.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {

				tryLogin();
			}
		});
	}

	/**
	 * This helper-method creates all widgets that are provided by this view.
	 */
	private void createWidgets() {

		grid = new GridPane();
		txtNickname = new TextField();
		lblNick = new Label(GUIText.NICKNAME.toString());
		txtPassword = new PasswordField();
		lblPassword = new Label(GUIText.PASSWORD.toString());
		txtCash = new TextField();
		lblCash = new Label(GUIText.ACTUALCASH.toString());
		txtCoins = new TextField();
		lblCoins = new Label(GUIText.COUNT.toString() + " " + GUIText.TOKEN.toString() + "n");
		btnLogin = new Button(GUIText.SIGNIN.toString());
		
		lblTopic = new Label(GUIText.SIGNIN.toString());
		sepTop = new Separator();
		sepBottom = new Separator();
		
		txtNickname.setText("HauptM421");
		txtCash.setText("0");
		txtCoins.setText("0");
	}

	/**
	 * This helper-method adds all created widgets to the scene.
	 */
	private void addWidgets() {

		grid.add(lblTopic, 0, rowCounter++);
		grid.add(sepTop, 0, rowCounter++);
		
		grid.add(lblNick, 0, rowCounter);
		grid.add(txtNickname, 1, rowCounter++);
		grid.add(lblPassword, 0, rowCounter);
		grid.add(txtPassword, 1, rowCounter++);
		grid.add(lblCash, 0, rowCounter);
		grid.add(txtCash, 1, rowCounter++);
		grid.add(lblCoins, 0, rowCounter);
		grid.add(txtCoins, 1, rowCounter++);
		grid.add(btnLogin, 1, rowCounter++);
		grid.add(sepBottom, 0, rowCounter++);
	}

	/**
	 * Sets up the different subclasses of <code>ErrorValidator</code> for the
	 * validation of the textfields.
	 */
	private void setupValidation() {

		valSup.registerValidator(txtNickname, true, new NameValidator());
		valSup.registerValidator(txtCash, true, DoubleNumberRangeValidator.createMinNumberRangeValidator(0));
		valSup.registerValidator(txtCoins, true, IntegerNumberRangeValidator.createMinNumberRangeValidator(0));
		valSup.registerValidator(txtPassword, true, new PasswordValidator());
	}
	
	@Override
	public void start(Stage primaryStage) {

		grid.getStyleClass().add("grid");
		
		scene = new Scene(grid);
		scene.getStylesheets().add(getClass().getResource(Configuration.STYLELOGIN).toExternalForm());
		scene.getStylesheets().add(getClass().getResource(Configuration.STYLEVALIDATION).toExternalForm());
		scene.getStylesheets().add(getClass().getResource(Configuration.STYLEROOT).toExternalForm());
		
		this.primaryStage = primaryStage;
//		primaryStage.setHeight(350);
//		primaryStage.setWidth(500);
		primaryStage.setScene(scene);
		primaryStage.setTitle(GUIText.SIGNIN.toString());
		primaryStage.setResizable(true);
		primaryStage.centerOnScreen();
		primaryStage.show();
	}
}
